#!/usr/bin/env python
# -*- coding: utf-8 -*-
# piwate is PIcasa Web Album Tag Output :-)

import piwalog
logger = piwalog.logging.getLogger("piwato")

# setdefaultencoding
# 通常は sys インポート後に setdefaultencodingは設定できないよう削除されてしまうため、
# reloadしてから設定する
# ElementTreeはこうしないとuncode文字列を扱えなかった
# stdin,stdout,stderrのencodingもここで再定義すると都度指定がいらなくなって楽だが、
# そうすると getpass がうまく動かない(入力文字列が画面に表示されてしまう)。
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

# コマンドプロンプトのエンコードを取得。Windowsでは通常'cp932'である。
# しかし、cp932が返るのに'mbcs'を指定しないとコケることがある。コンソール出力がコケた場合は考慮のこと
import locale
console_encode = locale.getpreferredencoding()
logger.debug("console_encode=%s"%console_encode)

import codecs
from optparse import OptionParser
from getpass import getpass
from xml.etree.ElementTree import *

import gdata.photos.service
import gdata.media
import gdata.geo

from piwacommon import *
import kml_class
import piwadb
import dsv


#get command line options...
#ユーザIDが指定されない場合はログインしない。その場合は取得できるのは access=publicだけとなる
#ログインできてもユーザの所有するalbumでない場合はログインしてないのと同様である
#ログインした場合はaccessを選ぶことができる(当該accessに合致したときだけ出力する)
parser = OptionParser(usage="%prog -u [-p] [-o] [-a] [-s] [-k] [-t]", version="%prog 0.4")

#auth
parser.add_option("-u", "--uid",  dest="uid",
                  help="login user id", default="", metavar="UID")
parser.add_option("-p", "--passwd",  dest="passwd",
                  help="login user password", default="", metavar="PASSWORD")
parser.add_option("-o", "--album-owner", dest="owner",
                  help="album owner(less then use uid(mail-address) user part)", default="", metavar="OWNER")

#output options
parser.add_option("-k", "--kml", dest="kml_file",
                  help="output filename for KML format", default="", metavar="FILENAME")

parser.add_option('-t', '--tag', dest='tag_file',
                  help='output filename for tag.', default="", metavar="FILENAME")

#detail options
parser.add_option('', '--album-only', dest='album_only', action='store_true', 
                  help="album only flag. no output photos.", default=False)

#access options
parser.add_option('', '--public-album', dest='access', action='store_const', const='public',
                  help='treated public album only', default='all')

parser.add_option('', '--protected-album', dest='access', action='store_const', const='protected',
                  help='treated protected album and public album', default='all')

parser.add_option('', '--all-album', dest='access', action='store_const', const='all',
                  help='treated all album (if authorized then public to private else public only)', default='all')

#extra
parser.add_option('', '--db-out', dest='dbout',
                  help='output sqlite3 DB to file(less than on memory, please specify none or empty file).',
                  metavar="FILENAME", default=":memory:")

(options, args) = parser.parse_args()

if options.uid != '' :
    if options.passwd == '' :
        options.passwd = getpass("login password:")
    if options.owner == '':
        options.owner = options.uid.split('@')[0]
else :
    if options.owner == '':
        parser.error("specify album owner or uid.\n")

#prepare
db = piwadb.PiwaDb(options.dbout)

#prepare for output(s)
if options.kml_file != '' :
    kml = kml_class.KMLTree()

#phot service object...
gd_client = gdata.photos.service.PhotosService()
gd_client.source = options.owner

if options.uid != '' :
    gd_client.email = options.uid
    gd_client.password = options.passwd
    try :
        import socket   # for socket.gaierror
        gd_client.ProgrammaticLogin()
    except gdata.service.BadAuthentication :
        logger.error(u"gdata.service.BadAuthentication")
        sys.stderr.write(u"Invalid login ID (-u) or password\n".encode(console_encode))
        sys.exit()
    except socket.gaierror, (errno, errstr):
        logger.error(u"socket.gaierror:(%s):%s"%(errno,errstr))
        sys.stderr.write((u"maybe cannot access internet. (socket.gaierror:(%s):%s)\n"%(errno,errstr)).encode(console_encode))
        sys.exit()

albums = gd_client.GetUserFeed(user=options.owner)
for album in albums.entry:
    album_id = uni(album.gphoto_id.text, GDATA_ENCODE)

    album_access = uni(album.access.text, GDATA_ENCODE)

    #checking access.... public -> only 'public', protected -> 'public' and 'protected'
    if invalidAccess(options.access, album_access) :
        continue
    
    album_title = uni(album.title.text, GDATA_ENCODE)
    album_pos = uni(album.geo.Point.pos.text, GDATA_ENCODE)
    album_link = uni(album.GetHtmlLink().href, GDATA_ENCODE)
    album_thumbnail = uni(album.media.thumbnail[0].url, GDATA_ENCODE)

    db.addAlbum(album_id, album_title, album_access, album_pos, album_link, album_thumbnail)
    logger.info(u'album %s access:%s geo:%s'%(album_title, album_access, album_pos))
    sys.stderr.write((u'album %s access:%s geo:%s\n'%(album_title, album_access, album_pos)).encode(console_encode))

    if options.kml_file != '' and album.geo.Point.pos.text != None :
        #print album.geo.Point.pos.text
        logger.debug(u"lbum.geo.Point.pos.text=%s"%(album.geo.Point.pos.text.decode(GDATA_ENCODE)))
        (latitude, longtitude) = album_pos.split(u' ')
        kml.addPlacemark(u'album:%s'%album_title,
                         u'<a href="%s"><img src="%s" alt="%s"></a>'%(album_link,album_thumbnail,album_title),
                         longtitude+u','+latitude)

    if options.album_only != True:    
        photos = gd_client.GetFeed(
            '/data/feed/api/user/%s/albumid/%s?kind=photo' % (
                options.owner, album.gphoto_id.text))
        for photo in photos.entry:
            photo_id = uni(photo.id.text, GDATA_ENCODE)
            photo_id = photo_id[photo_id.index(u'/photoid/')+len(u'/photoid/'):]

            photo_title = uni(photo.title.text, GDATA_ENCODE)
            photo_pos = uni(photo.geo.Point.pos.text, GDATA_ENCODE)
            photo_link = uni(photo.GetHtmlLink().href, GDATA_ENCODE)
            photo_thumbnail = uni(photo.media.thumbnail[0].url, GDATA_ENCODE)

            db.addPhoto(album_id, photo_id, photo_title, photo_pos, photo_link, photo_thumbnail)
            logger.info(u'\tphoto %s geo:%s' % (photo_title, photo_pos))
            sys.stderr.write((u'\tphoto %s geo:%s\n' % (photo_title, photo_pos)).encode(console_encode))
            #KML出力
            if options.kml_file != '' and photo.geo.Point.pos.text != None :
                (latitude, longtitude) = photo_pos.split(u' ')
                kml.addPlacemark(u'photo: %s'%photo_title,
                                 u'<a href="%s"><img src="%s" alt="%s"></a>'%(photo_link,photo_thumbnail,photo_title),
                                 longtitude+u','+latitude)

            #tag
            if options.tag_file != '' :
                photo_tags = gd_client.GetFeed('/data/feed/api/user/%s/albumid/%s/photoid/%s?kind=tag'
                                               % (options.owner, album.gphoto_id.text, photo.gphoto_id.text))
                for photo_tags_entry in photo_tags.entry:
                    #print "\t\tPhoto tag", photo_tags_entry.title.text
                    photo_tag = u''
                    if photo_tags_entry.title.text != None :
                        photo_tag = unicode(photo_tags_entry.title.text, TAG_ENCODE)
                        
                    db.addTag(photo_id, photo_tag)
                    logger.info(u'\t\ttag %s'%photo_tag)
                    sys.stderr.write((u'\t\ttag %s\n'%photo_tag).encode(console_encode))


if options.tag_file != '' and options.album_only != True:
    tagmap = db.tagmap()
    #logger.debug(u'tagmap:' + u','.join(getTagList(tagmap)) + u'\n')
    #sys.stderr.write((u'tagmap:' + u','.join(getTagList(tagmap)) + u'\n').encode(console_encode))
    tag_fd = codecs.open(options.tag_file, 'wb', encoding=TAG_ENCODE)


    dsv = dsv.DSV(FIXED_TITLE, map( lambda x: u'tag_'+x , getTagList(tagmap)))
    #dsv = dsv.DSV(FIXED_TITLE)
    
    #title...
    tag_fd.write((u'\t'.join(dsv.getTitle())+u'\n').encode(TAG_ENCODE))

    #data...
    for row in db.albumPhotoList() :
        dsv.fixed['album_id'] = row['album_id']
        dsv.fixed['album_title'] = row['album_title']
        dsv.fixed['album_link'] = row['album_link']
        dsv.fixed['album_thumbnail'] = row['album_thumbnail']
        dsv.fixed['photo_id'] = row['photo_id']
        dsv.fixed['photo_title'] = row['photo_title']
        dsv.fixed['photo_link'] = row['photo_link']
        dsv.fixed['photo_thumbnail'] = row['photo_thumbnail']
        
        dsv.clearVarData(db.tagCount())      #tag部分の内容を一旦クリア(プレースホルダを作る)

        for tag_row in db.tagList(row['photo_id']) :
            dsv.var[tagmap[tag_row['photo_tag']]] = tag_row['photo_tag']

        #logger.debug(u'taglist:' + u','.join(taglist) + u'\n')
        #sys.stderr.write((u'taglist:' + u','.join(taglist) + u'\n').encode(console_encode))

        tag_fd.write((u'\t'.join(dsv.getList()) + u'\n').encode(TAG_ENCODE))
    tag_fd.close()

if options.kml_file != '' :
    #KML to file
    fd = codecs.open(options.kml_file, 'wb', encoding=kml.ENCODE)
    fd.write(u'<?xml version="1.0" encoding="%s" ?>\n'%kml.ENCODE)
    kml.tree().write(fd, kml.ENCODE)
    fd.close()
